clc
clear

% op2.fileName = "FourCQUAD4_Static.op2";
% op2.fileName = "D:\Desktop\HM_OP2\FourCQUAD4_Static.op2"
% op2.fileName = "0516_x_norenum_222.op2"
op2.fileName = "FourCQUAD4_Static.op2"



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                              %
%              从这里往后开始读op2文件前面的一些东西                              %
%                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 判断大端序还是小端序
%%% 判断的基础是op2最开始的4个字节应该解析为4。先用大端序读
op2.fid = fopen(op2.fileName, 'r', 'ieee-be');
firstField = fread(op2.fid, 1, 'uint32');
if firstField == 4
    op2.machineFormat = 'big-endian';
elseif firstField == 67108864
    op2.machineFormat = 'little-endian';
    fclose(op2.fid);
    op2.fid = fopen(op2.fileName, 'r', 'ieee-le');
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 判断大端序还是小端序

fseek(op2.fid,0,-1);  %% 指针移动到文件最开头

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 日期
FieldHeader = fread(op2.fid, 1, 'int32');
dateLength = fread(op2.fid, 1, 'int32');
FieldTrailer = fread(op2.fid, 1, 'int32');

FieldHeader = fread(op2.fid, 1, 'int32');
mdy = fread(op2.fid, dateLength, 'int32');
FieldTrailer = fread(op2.fid, 1, 'int32');

op2.date = mdy;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 日期

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% nastran header
FieldHeader = fread(op2.fid, 1, 'int32');
dateLength = fread(op2.fid, 1, 'int32');
FieldTrailer = fread(op2.fid, 1, 'int32');

FieldHeader = fread(op2.fid, 1, 'int32');
nas_header = sprintf('%c', fread(op2.fid, 1*4*dateLength, 'char'));
FieldTrailer = fread(op2.fid, 1, 'int32');

op2.nas_header = nas_header;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% nastran header

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 版本号 OS2022
FieldHeader = fread(op2.fid, 1, 'int32');
dateLength = fread(op2.fid, 1, 'int32');
FieldTrailer = fread(op2.fid, 1, 'int32');

FieldHeader = fread(op2.fid, 1, 'int32');
os_version = sprintf('%c', fread(op2.fid, 1*4*dateLength, 'char'));
FieldTrailer = fread(op2.fid, 1, 'int32');

op2.os_version = os_version;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 版本号 OS2022




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                              %
%              从这里往后需要读两个标记-1和0,证明op2文件的前面定义结束了           %
%                                                                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Read end of record (expecting -1)
while true
    FieldHeader = fread(op2.fid, 1, 'int32');
    val = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');
    if val==-1
        EOR = true;
        break
    else
        FieldHeader = fread(op2.fid, 1, 'int32');
        tmp = sprintf('%c', fread(op2.fid, 1*4*val, 'char'));
        FieldTrailer = fread(op2.fid, 1, 'int32');
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Read end of record (expecting -1)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Read end of file/label (expecting 0)
FieldHeader = fread(op2.fid, 1, 'int32');
EOF = fread(op2.fid, 1, 'int32');
FieldTrailer = fread(op2.fid, 1, 'int32');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Read end of file/label (expecting 0)




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%              从这里往后开始循环读block{ii}.record{jj}.tableStart               %
%              从这里往后开始循环读block{ii}.record{jj}.tableLength              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 读block信息
blockID = 0;
while true
    blockID = blockID + 1;

    % 读block的名称长度
    FieldHeader = fread(op2.fid, 1, 'int32');
    blockNameLength = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    if blockNameLength == 0
        break
    end

    % 读block的名称
    FieldHeader = fread(op2.fid, 1, 'int32');
    name = sprintf('%c', fread(op2.fid, 1*4*blockNameLength, 'char'))
    FieldTrailer = fread(op2.fid, 1, 'int32');

    % 赋值
    op2.blockInfo(blockID).name = name;
    
    % Read end of record (expecting -1)
    while true
        FieldHeader = fread(op2.fid, 1, 'int32');
        val = fread(op2.fid, 1, 'int32');
        FieldTrailer = fread(op2.fid, 1, 'int32');
        if val==-1
            EOB = true;
            break
        else
            FieldHeader = fread(op2.fid, 1, 'int32');
            tmp = sprintf('%c', fread(op2.fid, 1*4*val, 'char'));
            FieldTrailer = fread(op2.fid, 1, 'int32');
        end
    end
    % Read end of block (expecting -1)


    % 读Trailer的长度
    FieldHeader = fread(op2.fid, 1, 'int32');
    trailerLength = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');


    % 读Trailer的值
    FieldHeader = fread(op2.fid, 1, 'int32');
    trailer = fread(op2.fid, trailerLength, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    % 赋值
	op2.blockInfo(blockID).trailer = trailer;

    % 看是不是Trailer结束了 (expecting -2)
    FieldHeader = fread(op2.fid, 1, 'int32');
    EOT = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    % Logical Record Type (expecting 1) 不懂
    FieldHeader = fread(op2.fid, 1, 'int32');
    LRT = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    % End of Logical Record Type (expecting 0)
    FieldHeader = fread(op2.fid, 1, 'int32');
    ELRT = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    % Gino file header 不知道是啥
    FieldHeader = fread(op2.fid, 1, 'int32');
    ginoLength = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    gino = cell(1,ginoLength);

    FieldHeader = fread(op2.fid, 1, 'int32');
    gino{1} = sprintf('%c', fread(op2.fid, 1*4*1, 'char'));
    gino{2} = sprintf('%c', fread(op2.fid, 1*4*1, 'char'));
    for ii = 1:(ginoLength-2)
        gino{ii+2} = fread(op2.fid, 1, 'int32');
    end
    FieldTrailer = fread(op2.fid, 1, 'int32');

    % 赋值
    op2.blockInfo(blockID).gino = gino;

    % End of Gino (expecting -3)
    FieldHeader = fread(op2.fid, 1, 'int32');
    EOG = fread(op2.fid, 1, 'int32');
    FieldTrailer = fread(op2.fid, 1, 'int32');

    %%% 开始记录当前block的record了
    recordID = 0;
	while true
		recordID = recordID + 1;

        % 查看当前记录的类型
        % Logical Record Type (0: table, 1: matrix column (string records), 
        % 2: factor matrix (string record), 3: factor matrix (matrix record))
        FieldHeader = fread(op2.fid, 1, 'int32');
        LRTLength = fread(op2.fid, 1, 'int32');
        FieldTrailer = fread(op2.fid, 1, 'int32');

        FieldHeader = fread(op2.fid, 1, 'int32');
        type = fread(op2.fid, LRTLength, 'int32');
        FieldTrailer = fread(op2.fid, 1, 'int32');

        op2.blockInfo(blockID).record(recordID).type = type;



		% 查看第1个Table的长度
        FieldHeader = fread(op2.fid, 1, 'int32');
        TableLength = fread(op2.fid, 1, 'int32');
        FieldTrailer = fread(op2.fid, 1, 'int32');
		if TableLength == 0
			break
        end

        % 记录这条Table的起始字节id与Table长度
        op2.blockInfo(blockID).record(recordID).TablesStart(1) = ftell(op2.fid);

        % If matrix, process differently
		if op2.blockInfo(blockID).record(recordID).type > 0
			TableLength = TableLength + 1;
        end
        op2.blockInfo(blockID).record(recordID).TablesLength(1) = TableLength;

        % 移动文件指针，跳过记录内容
        fseek(op2.fid, TableLength*4+8, 'cof');

        %%% 开始读这个Record的多个Table，如果TabLenTmp<0表明读到了4 -n 4
        curRecord = 0;
        FieldHeader = fread(op2.fid, 1, 'int32');
        TabLenTmp = fread(op2.fid, 1, 'int32');
        FieldTrailer = fread(op2.fid, 1, 'int32');


        while TabLenTmp > 0
			curRecord = curRecord + 1;

			op2.blockInfo(blockID).record(recordID).TablesStart(curRecord + 1) = ftell(op2.fid);
			op2.blockInfo(blockID).record(recordID).TablesLength(curRecord + 1) = TabLenTmp;

			% 移动文件指针，跳过记录内容
            fseek(op2.fid, TabLenTmp*4+8, 'cof');

            FieldHeader = fread(op2.fid, 1, 'int32');
            TabLenTmp = fread(op2.fid, 1, 'int32');
            FieldTrailer = fread(op2.fid, 1, 'int32');

        end % table
    end  % record
end  % block
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 读block信息



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%              从这里往后开始解析各个block的内容                                  %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% 见 [OP2文件格式与解析](siyuan://blocks/20250102183154-ji12gnw)

%%% 解析 OES
blockinfo = op2.blockInfo;
for ii = 1:length(blockinfo)
    ablockinfo = blockinfo(ii);
    switch ablockinfo.name(1:3)
        case "OES"
            break
            ablock = ReadBlock_OES(ablockinfo);
        otherwise 
            fprintf("%s 数据块暂未解析\n", ablockinfo.name)
    end
end



